home *** CD-ROM | disk | FTP | other *** search
- // Copyright (C) 1996, 1997 Meta Four Software. All rights reserved.
- //
- // Recursive directory scanner sample code
- //
- //! rev="$Id: catalog.cpp,v 1.3 1997/05/27 00:06:33 jcw Rel $"
-
- /////////////////////////////////////////////////////////////////////////////
- //
- // The following two globally accesible routines are defined below:
- //
- // c4_View fScanDirectories(const char* path_);
- // c4_String fFullPath(c4_View& dirs_, int dirNum_);
- //
- // The fScanDirectories routine does all the work, and completely hides all
- // Windows 16/32 specifics by returning a generalized catalog tree object.
- // In contrast with normal C++ conventions, nearly all MetaKit objects are
- // reference counted. This takes care of fully automatic cleanup after use.
- //
- // The structure of the object returned by fScanDirectories is as follows:
- //
- // Property Type Description
- // ======== ==== ===========
- //
- // dirs nested Contains 1 record per directory
- // parent integer Index of parent entry
- // name string Name of this directory
- // files nested Contains 1 record per file entry
- // name string Name of this file
- // size string File size
- // date integer Modification date (DOS format 7+4+5 bits)
- //
- // The first directory entry (entry 0) is special: the parent is set to zero
- // (points to itself), and the name is the base path name (see path_ arg).
- //
- // In C++ notation, a declaration for this object would be something like:
- //
- // struct
- // {
- // int parent;
- // char* name;
- //
- // struct
- // {
- // char* name;
- // long size;
- // int date;
- //
- // } files []; // variable size, not allowed in C++
- //
- // } dirs [];
- //
- /////////////////////////////////////////////////////////////////////////////
-
- #include "stdafx.h"
- #include "catalog.h"
-
- // forward declaration
- static void ScanSubDir(c4_View&, int, const c4_String&);
-
- /////////////////////////////////////////////////////////////////////////////
- // Property definitions
-
- c4_ViewProp pFiles ("files");
- c4_IntProp pParent ("parent"),
- pSize ("size"),
- pDate ("date");
- c4_StringProp pName ("name");
-
- /////////////////////////////////////////////////////////////////////////////
- // Scan a directory tree and return a corresponding structure for it
-
- c4_View fScanDirectories(const char* path_)
- {
- // Start with a view containing the root directory entry
- c4_View dirs;
- dirs.Add(pName [path_]);
-
- // This loop "automagically" handles the recursive traversal of all
- // subdirectories. The trick is that each scan may add new entries
- // at the end, causing this loop to continue (GetSize() changes!).
-
- for (int i = 0; i < dirs.GetSize(); ++i)
- {
- c4_String path = fFullPath(dirs, i);
-
- TRACE("Scanning '%s' ...\n", (const char*) path);
- ScanSubDir(dirs, i, path);
- }
-
- // The returned object contains the entire directory tree.
- // Everything is automatically destroyed when no longer referenced.
- return dirs;
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // Reconstruct the full path name from a subdirectory index in the tree
-
- c4_String fFullPath(c4_View& dirs_, int dirNum_)
- {
- // Prefix all parent dir names until the root level is reached
- c4_String path;
- for (;;)
- {
- path = pName (dirs_[dirNum_]) + "\\" + path;
-
- if (dirNum_ == 0)
- return path; // this result always has a trailing backslash
-
- dirNum_ = (int) pParent (dirs_[dirNum_]);
- }
- }
-
- /////////////////////////////////////////////////////////////////////////////
- // There are two versions of ScanSubDir, one for Win32 and one for Win16
-
- #ifdef _WIN32
-
- // Convert a Win32 filedate back to the good old DOS format
- static WORD DosDate(FILETIME& ft)
- {
- SYSTEMTIME st;
-
- if (!FileTimeToSystemTime(&ft, &st))
- return 0;
-
- return (WORD) (((st.wYear-1980) << 9) | (st.wMonth << 5) | st.wDay);
- }
-
- // Scan subdirectory and update the directory structure
- static void ScanSubDir(c4_View& dirs_, int dirNum_, const c4_String& path_)
- {
- WIN32_FIND_DATA fd;
-
- HANDLE h = FindFirstFile(path_ + "*", &fd);
- if (h)
- {
- // Some notes on efficiency:
- //
- // 1) It is probably faster to fill a view with data, and
- // then store it in a persistent field, than to modify
- // persistent structures in place. In this example, this
- // is needed anyway, since we also sort all filenames.
- //
- // 2) If possible, avoid constructing rows inside a loop.
- // For that reason, both 'prop [const]' and 'row + row'
- // are relatively inefficient.
-
- // c4_View files = pFiles (dirs_[dirNum_]);
- c4_View files;
- c4_Row dir, file;
-
- do
- {
- if (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
- {
- if (fd.cFileName[0] == '.')
- continue;
-
- // dirs_.Add(pParent [dirNum_] + pName [fd.cFileName]);
- pParent (dir) = dirNum_;
- pName (dir) = fd.cFileName;
- dirs_.Add(dir);
- }
- else
- {
- // files.Add(pName [fd.cFileName] + pSize [fd.nFileSizeLow]
- // + pDate [DosDate(fd.ftLastWriteTime)]);
- pName (file) = fd.cFileName;
- pSize (file) = fd.nFileSizeLow;
- pDate (file) = DosDate(fd.ftLastWriteTime);
- files.Add(file);
- }
-
- } while (FindNextFile(h, &fd));
-
- pFiles (dirs_[dirNum_]) = files.SortOn(pName);
-
- FindClose(h);
- }
- }
-
- #else
-
- #include <dos.h>
-
- // Scan subdirectory and update the directory structure
- static void ScanSubDir(c4_View& dirs_, int dirNum_, const c4_String& path_)
- {
- _find_t fd;
-
- if (_dos_findfirst(path_ + "*.*", _A_SUBDIR, &fd) == 0)
- {
- c4_View files;
- c4_Row dir, file;
-
- do
- {
- if (fd.attrib & _A_SUBDIR)
- {
- if (fd.name[0] == '.')
- continue;
-
- pParent (dir) = dirNum_;
- pName (dir) = fd.name;
- dirs_.Add(dir);
- }
- else
- {
- pName (file) = fd.name;
- pSize (file) = fd.size;
- pDate (file) = fd.wr_date;
- files.Add(file);
- }
-
- } while (_dos_findnext(&fd) == 0);
-
- pFiles (dirs_[dirNum_]) = files.SortOn(pName);
- }
- }
-
- #endif
-
- /////////////////////////////////////////////////////////////////////////////
-